package com.topisv.tms.service.md;

import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.xml.bind.JAXB;

import org.apache.http.client.fluent.Request;
import org.apache.http.client.fluent.Response;
//import org.fusesource.hawtbuf.ByteArrayOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.EdiGoodsSku;
import com.topisv.tms.entity.EdiOrder;
import com.topisv.tms.entity.EdiOrderItem;
import com.topisv.tms.entity.stock.instorage.InstorageBill;
import com.topisv.tms.entity.stock.instorage.InstorageCountItem;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillItemPre;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillPre;
import com.topisv.tms.entity.stock.instorage.pre.PreInBill;
import com.topisv.tms.entity.task.MdSendOutTask;
import com.topisv.tms.entity.work.WorkOrder;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.stock.instorage.InstorageBillDao;
import com.topisv.tms.repository.stock.instorage.InstorageCountItemDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillPreDao;
import com.topisv.tms.repository.task.MdSendOutTaskDao;
import com.topisv.tms.repository.work.WorkOrderDao;
import com.topisv.tms.rest.entity.md.request.TransferData;
import com.topisv.tms.service.EdiOrderService;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.service.stock.instorage.InstorageBillService;
import com.topisv.tms.service.vo.invoice.MDParam;
import com.topisv.tms.tools.TransferHelper;
import com.topisv.tms.utils.EdiOrderUtil;
import com.topisv.tms.utils.SystemUtil;
import com.topisv.tms.utils.WmsContants;
import com.topisv.tms.utils.enums.MDDocumentType;
import com.topisv.tms.utils.enums.MDOrderType;
import com.topisv.tms.utils.enums.TaskStatus;

@Component
public class MdSendOutTaskService extends BaseService {

	@Autowired
	private MdSendOutTaskDao mdSendOutTaskDao;
	@Autowired
	private EdiOrderService ediOrderService;
	@Autowired
	private WorkOrderDao workOrderDao;
	@Autowired
	private InstorageBillService instorageBillService;
	@Autowired
	private InstorageCountItemDao instorageCountItemDao;
	@Autowired
	private InstorageBillPreDao instorageBillPreDao;
	@Autowired
	private InstorageBillDao instorageBillDao;
	@Autowired
	private EdiGoodsSkuDao ediGoodsSkuDao;
	@Autowired
	private TransferHelper transferHelper;
	@PersistenceContext
	private EntityManager em;
	private String node;
	
	@Transactional(readOnly = false)
	public void save(MdSendOutTask task) {
		mdSendOutTaskDao.save(task);
	}
	/**
	 * 查找所有未处理的任务
	 * @param pagzSize
	 * @return List<MdSendOutTask>
	 */
	@Transactional(readOnly = false)
	public List<MdSendOutTask> findLockedTask() {
		List<MdSendOutTask> tasks = mdSendOutTaskDao.findTask(getNode());
		if (!tasks.isEmpty()) {
			mdSendOutTaskDao.update(getNode(), EdiOrderUtil.findIds(tasks));
		}
		return tasks;
	}
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void lockData(int pageSize) {
		Query querySql = em.createNativeQuery("select t.id from tt_md_out_task t  where deal_ip is null and deal_status=0 and work_num=done_num order by id desc limit ?1");
		querySql.setParameter(1, pageSize);
		List<Long> idRs = querySql.getResultList();
		if (!idRs.isEmpty()) {
			Query updateSql = em.createNativeQuery("update tt_md_out_task t set t.deal_ip = ?1,t.deal_time = now(),deal_status=1 where t.id in ?2 and deal_status=0");
			updateSql.setParameter(1, getNode());
			updateSql.setParameter(2, idRs);
			updateSql.executeUpdate();
		}
	}
	/**
	 * 处理任务
	 * @param task
	 * @throws Exception 
	 */
	@Transactional(readOnly = false)
	public void dealTask(MdSendOutTask task) throws Exception{
		if (!getNode().equals(task.getDealIp())) {
			return;
		}
		task.setDealStatus(TaskStatus.SUCCESS.getStatus());
		if (MDOrderType.SALE.getType().equals(task.getOrderType())) {
			doDealTask(findOrderTaskData(task), task);
		} else if (MDOrderType.PURCHASE.getType().equals(task.getOrderType())) {
			doDealTask(findPreOrderTaskData(task), task);
		} else if (MDOrderType.RETURN.getType().equals(task.getOrderType())) {
			doDealTask(findBackTaskData(task), task);
		}
		save(task);
	}
	
	private void doDealTask(TransferData transferData,MdSendOutTask task) throws Exception{
		if (transferData == null) {
			return;
		}
		ByteArrayOutputStream bais = new ByteArrayOutputStream(1024);
		JAXB.marshal(transferData, bais);
		Response response = sendOutMessage(bais);
		com.topisv.tms.rest.entity.md.response.Response mdResponse = JAXB.unmarshal(response.returnContent().asStream(), com.topisv.tms.rest.entity.md.response.Response.class);
		if (!mdResponse.isFlag()) {
			log.error(new StringBuilder().append("error====[customerNO:").append(task.getCustomerOrderNo()).append("] deal fail.").toString());
			log.error(new StringBuilder().append("errorcode:").append(mdResponse.getErroCode()).append("\terrormsg:").append(mdResponse.getErro()).toString());
			StringWriter sw = new StringWriter();
			JAXB.marshal(transferData, sw);
			log.error(new StringBuilder().append("request xml is:\n").append(sw.toString()).toString());
			throw new PaiUException(ErrorCode.DATA_ERROR);
		}
	}
	
	private TransferData findOrderTaskData(MdSendOutTask task){
		List<WorkOrder> workOrders = workOrderDao.loadByCustomerOrdenoNormal(task.getCustomerOrderNo(),WmsContants.CUSTOMER_MID);
		Map<String,EdiGoodsSku> sku2BarMap = new HashMap<String, EdiGoodsSku>();
		for (WorkOrder workOrder : workOrders) {
			EdiOrder ediOrder = ediOrderService.findByOrderNoDetail(workOrder.getOrder().getOrdeno());
			workOrder.setOrder(ediOrder);
			for (EdiOrderItem item : ediOrder.getOrderItems()) {
				if (sku2BarMap.get(item.getSku()) == null) {
					EdiGoodsSku ediGoodsSku = ediGoodsSkuDao.findByCustomerCodeAndSku(workOrder.getCustomerCode(), item.getSku());
					sku2BarMap.put(ediGoodsSku.getSku(), ediGoodsSku);
				}
			}
		}
		Collections.sort(workOrders, new Comparator<WorkOrder>() {
			@Override
			public int compare(WorkOrder o1, WorkOrder o2) {
				List<EdiOrderItem> orderItems1 = o1.getOrder().getOrderItems();
				List<EdiOrderItem> orderItems2 = o2.getOrder().getOrderItems();
				EdiOrderItem item1 = findItem(orderItems1);
				EdiOrderItem item2 = findItem(orderItems2);
				return item1.getPri() == null ? 1 : item2.getPri() == null ? -1 : item2.getPri().compareTo(item1.getPri());
			}
		});
		
		return transferHelper.bulidConfirmSaleData(MDDocumentType.ORDERCONFIM, MDOrderType.SALE, workOrders, sku2BarMap);
	}
	
	private static EdiOrderItem findItem(List<EdiOrderItem> orderItems){
		EdiOrderItem other = null;
		for (EdiOrderItem item : orderItems) {
			if (other == null || other.getPri() == null) {
				other = item;
			} else if (item.getPri() != null && other.getPri().compareTo(item.getPri()) < 0) {
				other = item;
			}
		}
		return other;
	}
	
	private TransferData findPreOrderTaskData(MdSendOutTask task) {
		InstorageBillPre billPre = instorageBillPreDao.findByCustomerCodeAndCustomerOrderNo(WmsContants.CUSTOMER_MID,task.getCustomerOrderNo());
		List<PreInBill> preInBills = billPre.getPreInBills();
		for (PreInBill preInBill : preInBills) {
			InstorageBill bill = instorageBillService.loadBillByCode(preInBill.getInBillCode());
			if("1".equals(bill.getSyncMdFlag())){
				continue;
			}
			bill.setSyncMdFlag("1");
			instorageBillDao.save(bill);
			List<InstorageCountItem> countItems = instorageCountItemDao.loadByBillCode(preInBill.getInBillCode());
			List<InstorageBillItemPre> itemPres = bill.getPreBill().getBillItem();
			Map<String,EdiGoodsSku> sku2BarMap = new HashMap<String, EdiGoodsSku>();
			for (InstorageBillItemPre item : itemPres) {
				if (sku2BarMap.get(item.getSkuCode()) == null) {
					EdiGoodsSku ediGoodsSku = ediGoodsSkuDao.findByCustomerCodeAndSku(billPre.getCustomerCode(), item.getSkuCode());
					sku2BarMap.put(ediGoodsSku.getSku(), ediGoodsSku);
				}
			}
			return transferHelper.bulidConfirmPurchaseData(MDDocumentType.ORDERCONFIM, MDOrderType.PURCHASE, bill, countItems, sku2BarMap);
		}
		return null;
	}

	private TransferData findBackTaskData(MdSendOutTask task) {
		InstorageBillPre billPre = instorageBillPreDao.findByCustomerCodeAndCustomerOrderNo(WmsContants.CUSTOMER_MID,task.getCustomerOrderNo());
		List<PreInBill> preInBills = billPre.getPreInBills();
		for (PreInBill preInBill : preInBills) {
			InstorageBill bill = instorageBillService.loadBillByCode(preInBill.getInBillCode());
			if("1".equals(bill.getSyncMdFlag())){
				continue;
			}
			bill.setSyncMdFlag("1");
			instorageBillDao.save(bill);
			List<InstorageCountItem> countItems = instorageCountItemDao.loadByBillCode(preInBill.getInBillCode());
			List<InstorageBillItemPre> itemPres = bill.getPreBill().getBillItem();
			Map<String,EdiGoodsSku> sku2BarMap = new HashMap<String, EdiGoodsSku>();
			for (InstorageBillItemPre item : itemPres) {
				if (sku2BarMap.get(item.getSkuCode()) == null) {
					EdiGoodsSku ediGoodsSku = ediGoodsSkuDao.findByCustomerCodeAndSku(billPre.getCustomerCode(), item.getSkuCode());
					sku2BarMap.put(ediGoodsSku.getSku(), ediGoodsSku);
				}
			}
			return transferHelper.bulidConfirmBackData(MDDocumentType.ORDERCONFIM, MDOrderType.RETURN, bill, countItems, sku2BarMap);
		}
		return null;
	}
	
	private Response sendOutMessage(ByteArrayOutputStream bais) throws Exception{
		String token = new StringBuilder().append(MDParam.USERNAME).append(":").append(MDParam.PASSWORD).toString();
		return Request.Post(MDParam.URL).connectTimeout(10000)
				.addHeader("Authorization", new StringBuilder().append("Basic ").append(SystemUtil.getBASE64(token)).toString())
				.addHeader("Content-Type", "text/xml; charset=utf-8").bodyByteArray(bais.toByteArray()).execute();
	}
	/**
	 * 更新数量
	 * @param customerOrderNo
	 * @param num
	 * @return int
	 */
	@Transactional(readOnly = false)
	public int updateDoneNum(String customerOrderNo,int num){
		return mdSendOutTaskDao.updateDoneNum(customerOrderNo,num);
	}
	/**
	 * 删除任务
	 * @param customerOrderNo
	 * @return int
	 */
	@Transactional(readOnly = false)
	public int deleteTaskByCusOrderNo(String customerOrderNo){
		return mdSendOutTaskDao.deleteTaskByCusOrderNo(customerOrderNo);
	}
	public String getNode() {
		if (node == null) {
			String name = ManagementFactory.getRuntimeMXBean().getName();
			node = name.substring(name.indexOf("@") + 1);
		}
		return node;
	}
}
